package com.frontend.authservice.Config;

import com.frontend.authservice.service.Impl.security.CustomClientDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.client.InMemoryClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import java.util.Arrays;
import java.util.Map;
import java.util.Set;

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    // 注入自定义的客户端详情服务
    @Autowired
    private CustomClientDetailsService customClientDetailsService;

    // 配置客户端信息（可替换为数据库存储）
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(customClientDetailsService);


//        clients.inMemory()
//                //这个的意思是网关要带着gateway-client和gateway-secret才能访问
//                .withClient("gateway-client")  // 网关客户端ID
//                .secret(passwordEncoder.encode("gateway-secret")) // 网关客户端密钥
//                //password - 密码模式：
//                //网关可以使用用户的用户名和密码来获取访问令牌
//                //适用于用户直接登录的场景
//                //refresh_token - 刷新令牌模式当访问令牌过期后，可以使用刷新令牌获取新的访问令牌无需用户重新输入密码(给令牌续时间)
//                //client_credentials - 客户端凭证模式：
//                //网关可以仅使用自己的身份（客户端ID和密码）获取令牌
//                //适用于不需要用户身份的后台服务间调用
//                .authorizedGrantTypes("password", "refresh_token", "client_credentials")
//                //代表着当前认证的_token 只能read: 读取权限 - 可以查看、获取数据
//                //代表着当前认证的_token 只能write: 写入权限 - 可以创建、修改、删除数据
//                .scopes("read", "write")
//                //当网关获取到访问令牌后，这个令牌只能在1小时内使用
//                //1小时后令牌过期，无法再用来访问受保护的资源
//                //过期后需要重新获取令牌或使用刷新令牌
//                .accessTokenValiditySeconds(3600)  // 1小时有效期
//                //当访问令牌过期后，在30天内都可以使用刷新令牌获取新的访问令牌(就是三十天内可以再来给令牌续期)
//                //30天后刷新令牌也过期，用户需要重新登录
//                //刷新令牌通常比访问令牌有效期长得多
//                .refreshTokenValiditySeconds(2592000);  // 30天刷新令牌有效期
    }

    // 配置端点
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                //配置认证管理器
                //用于验证用户身份（用户名和密码是否正确）
                //当使用 password 模式时需要用到UserDetailsService：存储和提供用户信息（包括密码）
                //AuthenticationManager：负责验证过程，需要使用 UserDetailsService 提供的信息来完成验证

                .authenticationManager(authenticationManager)
                //配置认证管理器
                //用于验证用户身份（用户名和密码是否正确）
                //当使用 password 模式时需要用到
                .userDetailsService(userDetailsService)
                .tokenStore(tokenStore())
                .tokenServices(tokenServices()) // 添加这行
                .accessTokenConverter(accessTokenConverter());
    }

    // 使用JWT存储令牌
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    // JWT转换器（生产环境使用非对称加密）
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        // 显式指定签名算法为HMACSHA256
        converter.setSigningKey("my-secret-key-12345");

        // 如果你想查看实际使用的算法，可以添加以下代码进行调试
        System.out.println("JWT Access Token Converter created with signing key");
        return converter;
    }
    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setTokenStore(tokenStore());
        services.setSupportRefreshToken(true);
        services.setClientDetailsService(customClientDetailsService);
        services.setTokenEnhancer(accessTokenConverter());
        return services;
    }

    // 配置安全约束
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
//        security
//                // // 白名单：任何人都可以访问
//                .tokenKeyAccess("permitAll()")  // 公开公钥端点
//                // 白名单：只有认证用户可以访问
//                .checkTokenAccess("isAuthenticated()");  // 令牌验证端点需要认证
        security

                .tokenKeyAccess("permitAll()")  // 公开公钥端点
                .checkTokenAccess("permitAll()")  // 允许所有客户端检查令牌

                .allowFormAuthenticationForClients(); // 允许表单认证客户端
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 确保使用 BCrypt
    }










}